home *** CD-ROM | disk | FTP | other *** search
/ QRZ! Ham Radio 1 / QRZ Ham Radio Callsign Database - December 1993.iso / ucsd / packet / tcpip / amiga / asrc29k.lha / mbuf.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-01-08  |  9.0 KB  |  455 lines

  1. /* Primitive mbuf allocate/free routines */
  2.  
  3. #include <stdio.h>
  4. #include "global.h"
  5. #include "mbuf.h"
  6. #include "proc.h"
  7.  
  8. /* Allocate mbuf with associated buffer of 'size' bytes */
  9. struct mbuf *alloc_mbuf(size)
  10. register int16 size;
  11. {
  12.     register struct mbuf *bp;
  13.  
  14.     if((bp = (struct mbuf *)malloc((unsigned)(size + sizeof(struct mbuf)))) == NULLBUF)
  15.         return NULLBUF;
  16.  
  17.     bp->next = bp->anext = NULLBUF;
  18.     if((bp->size = size) != 0){
  19.         bp->data = (char *)(bp + 1);
  20.     } else {
  21.         bp->data = NULLCHAR;
  22.     }
  23.     bp->refcnt = 1;
  24.     bp->dup = NULLBUF;
  25.     bp->cnt = 0;
  26.     return bp;
  27. }
  28.  
  29. /* Allocate mbuf, waiting if memory is unavailable */
  30. struct mbuf *ambufw(size)
  31. int16 size;
  32. {
  33.     register struct mbuf *bp;
  34.  
  35.     bp = (struct mbuf *)mallocw((unsigned)(size + sizeof(struct mbuf)));
  36.  
  37.     /* Clear just the header portion */
  38.     memset((char *)bp,0,sizeof(struct mbuf));
  39.     if((bp->size = size) != 0)
  40.         bp->data = (char *)(bp + 1);
  41.     bp->refcnt++;
  42.     return bp;
  43. }
  44.  
  45. /* Decrement the reference pointer in an mbuf. If it goes to zero,
  46.  * free all resources associated with mbuf.
  47.  * Return pointer to next mbuf in packet chain
  48.  */
  49. struct mbuf *free_mbuf(bp)
  50. register struct mbuf *bp;
  51. {
  52.     register struct mbuf *bp1 = NULLBUF;
  53.  
  54.     if(bp != NULLBUF){
  55.         bp1 = bp->next;
  56.         /* Follow indirection, if any */
  57.         free_mbuf(bp->dup);
  58.  
  59.         if(--bp->refcnt == 0)
  60.             free((char *)bp);
  61.     }
  62.     return bp1;
  63. }
  64.  
  65. /* Free packet (a chain of mbufs). Return pointer to next packet on queue,
  66.  * if any
  67.  */
  68. struct mbuf *free_p(bp)
  69. register struct mbuf *bp;
  70. {
  71.     register struct mbuf *abp;
  72.  
  73.     if(bp == NULLBUF)
  74.         return NULLBUF;
  75.     abp = bp->anext;
  76.     while(bp != NULLBUF)
  77.         bp = free_mbuf(bp);
  78.     return abp;
  79. }        
  80. /* Free entire queue of packets (of mbufs) */
  81. void free_q(q)
  82. struct mbuf **q;
  83. {
  84.     register struct mbuf *bp;
  85.  
  86.     while((bp = dequeue(q)) != NULLBUF)
  87.         free_p(bp);
  88. }
  89.  
  90. /* Count up the total number of bytes in a packet */
  91. int16 len_p(bp)
  92. register struct mbuf *bp;
  93. {
  94.     register int16 cnt = 0;
  95.  
  96.     while(bp != NULLBUF){
  97.         cnt += bp->cnt;
  98.         bp = bp->next;
  99.     }
  100.     return cnt;
  101. }
  102. /* Count up the number of packets in a queue */
  103. int16 len_q(bp)
  104. register struct mbuf *bp;
  105. {
  106.     register int16 cnt;
  107.  
  108.     for(cnt=0;bp != NULLBUF;cnt++,bp = bp->anext)
  109.         ;
  110.     return cnt;
  111. }
  112. /* Trim mbuf to specified length by lopping off end */
  113. void trim_mbuf(bpp,length)
  114. struct mbuf **bpp;
  115. int16 length;
  116. {
  117.     register int16 tot = 0;
  118.     register struct mbuf *bp;
  119.  
  120.     if(bpp == NULLBUFP || *bpp == NULLBUF)
  121.         return;    /* Nothing to trim */
  122.  
  123.     if(length == 0){
  124.         /* Toss the whole thing */
  125.         free_p(*bpp);
  126.         *bpp = NULLBUF;
  127.         return;
  128.     }
  129.     /* Find the point at which to trim. If length is greater than
  130.      * the packet, we'll just fall through without doing anything
  131.      */
  132.     for( bp = *bpp; bp != NULLBUF; bp = bp->next){
  133.         if(tot + bp->cnt < length){
  134.             tot += bp->cnt;
  135.         } else {
  136.             /* Cut here */
  137.             bp->cnt = length - tot;
  138.             free_p(bp->next);
  139.             bp->next = NULLBUF;
  140.             break;
  141.         }
  142.     }
  143. }
  144. /* Duplicate/enqueue/dequeue operations based on mbufs */
  145.  
  146. /* Duplicate first 'cnt' bytes of packet starting at 'offset'.
  147.  * This is done without copying data; only the headers are duplicated,
  148.  * but without data segments of their own. The pointers are set up to
  149.  * share the data segments of the original copy. The return pointer is
  150.  * passed back through the first argument, and the return value is the
  151.  * number of bytes actually duplicated.
  152.  */
  153. int16 dup_p(hp,bp,offset,cnt)
  154. struct mbuf **hp;
  155. register struct mbuf *bp;
  156. register int16 offset;
  157. register int16 cnt;
  158. {
  159.     register struct mbuf *cp;
  160.     int16 tot;
  161.  
  162.     if(cnt == 0 || bp == NULLBUF || hp == NULLBUFP){
  163.         if(hp != NULLBUFP)
  164.             *hp = NULLBUF;
  165.         return 0;
  166.     }
  167.     if((*hp = cp = alloc_mbuf(0)) == NULLBUF){
  168.         return 0;
  169.     }
  170.     /* Skip over leading mbufs that are smaller than the offset */
  171.     while(bp != NULLBUF && bp->cnt <= offset){
  172.         offset -= bp->cnt;
  173.         bp = bp->next;
  174.     }
  175.     if(bp == NULLBUF){
  176.         free_mbuf(cp);
  177.         *hp = NULLBUF;
  178.         return 0;    /* Offset was too big */
  179.     }
  180.     tot = 0;
  181.     for(;;){
  182.         /* Make sure we get the original, "real" buffer (i.e. handle the
  183.          * case of duping a dupe)
  184.          */
  185.         if(bp->dup != NULLBUF)
  186.             cp->dup = bp->dup;
  187.         else
  188.             cp->dup = bp;
  189.  
  190.         /* Increment the duplicated buffer's reference count */
  191.         cp->dup->refcnt++;
  192.  
  193.         cp->data = bp->data + offset;
  194.         cp->cnt = min(cnt,bp->cnt - offset);
  195.         offset = 0;
  196.         cnt -= cp->cnt;
  197.         tot += cp->cnt;
  198.         bp = bp->next;
  199.         if(cnt == 0 || bp == NULLBUF || (cp->next = alloc_mbuf(0)) == NULLBUF)
  200.             break;
  201.         cp = cp->next;
  202.     }
  203.     return tot;
  204. }
  205.  
  206. /* Copy first 'cnt' bytes of packet into a new, single mbuf */
  207. struct mbuf *copy_p(bp,cnt)
  208. register struct mbuf *bp;
  209. register int16 cnt;
  210. {
  211.     register struct mbuf *cp;
  212.     register char *wp;
  213.     register int16 n;
  214.  
  215.     if(bp == NULLBUF || cnt == 0 || (cp = alloc_mbuf(cnt)) == NULLBUF)
  216.         return NULLBUF;
  217.     wp = cp->data;
  218.     while(cnt != 0 && bp != NULLBUF){
  219.         n = min(cnt,bp->cnt);
  220.         memcpy(wp,bp->data,n);
  221.         wp += n;
  222.         cp->cnt += n;
  223.         cnt -= n;
  224.         bp = bp->next;
  225.     }
  226.     return cp;
  227. }
  228.  
  229. /* Copy and delete "cnt" bytes from beginning of packet. Return number of
  230.  * bytes actually pulled off
  231.  */
  232. int16 pullup(bph,buf,cnt)
  233. struct mbuf **bph;
  234. char *buf;
  235. int16 cnt;
  236. {
  237.     register struct mbuf *bp;
  238.     int16 n,tot;
  239.  
  240.     tot = 0;
  241.     if(bph == NULLBUFP)
  242.         return 0;
  243.     while(*bph != NULLBUF && cnt != 0){
  244.         bp = *bph;
  245.         n = min(cnt,bp->cnt);
  246.         if(buf != NULLCHAR){
  247.             if(n == 1)    /* Common case optimization */
  248.                 *buf = *bp->data;
  249.             else if(n > 1)
  250.                 memcpy(buf,bp->data,n);
  251.             buf += n;
  252.         }
  253.         tot += n;
  254.         cnt -= n;
  255.         bp->data += n;
  256.         bp->cnt -= n;        
  257.         if(bp->cnt == 0){
  258.             /* If this is the last mbuf of a packet but there
  259.              * are others on the queue, return a pointer to
  260.              * the next on the queue. This allows pullups to
  261.              * to work on a packet queue
  262.              */
  263.             if(bp->next == NULLBUF && bp->anext != NULLBUF){
  264.                 *bph = bp->anext;
  265.                 free_mbuf(bp);
  266.             } else
  267.                 *bph = free_mbuf(bp);
  268.         }
  269.     }
  270.     return tot;
  271. }
  272.  
  273. /* Append mbuf to end of mbuf chain */
  274. void append(bph,bp)
  275. struct mbuf **bph;
  276. struct mbuf *bp;
  277. {
  278.     register struct mbuf *p;
  279.  
  280.     if(bph == NULLBUFP || bp == NULLBUF)
  281.         return;
  282.     if(*bph == NULLBUF){
  283.         /* First one on chain */
  284.         *bph = bp;
  285.     } else {
  286.         for(p = *bph ; p->next != NULLBUF ; p = p->next)
  287.             ;
  288.         p->next = bp;
  289.     }
  290. }
  291.  
  292. /* Insert specified amount of contiguous new space at the beginning of an
  293.  * mbuf chain. If enough space is available in the first mbuf, no new space
  294.  * is allocated. Otherwise a mbuf of the appropriate size is allocated and
  295.  * tacked on the front of the chain.
  296.  *
  297.  * This operation is the logical inverse of pullup(), hence the name.
  298.  */
  299. struct mbuf *pushdown(bp,size)
  300. register struct mbuf *bp;
  301. int16 size;
  302. {
  303.     register struct mbuf *nbp;
  304.  
  305.     /* Check that bp is real, that it hasn't been duplicated, and
  306.      * that it itself isn't a duplicate before checking to see if
  307.      * there's enough space at its front.
  308.      */
  309.     if(bp != NULLBUF && bp->refcnt == 1 && bp->size != 0
  310.      && bp->data - (char *)(bp+1) >= size){
  311.         /* No need to alloc new mbuf, just adjust this one */
  312.         bp->data -= size;
  313.         bp->cnt += size;
  314.     } else {
  315.         if((nbp = alloc_mbuf(size)) != NULLBUF){
  316.             nbp->next = bp;
  317.             nbp->cnt = size;
  318.             bp = nbp;
  319.         } else {
  320.             bp = NULLBUF;
  321.         }
  322.     }
  323.     return bp;
  324. }
  325.  
  326. /* Append packet to end of packet queue */
  327. void enqueue(q,bp)
  328. struct mbuf **q;
  329. struct mbuf *bp;
  330. {
  331.     register struct mbuf *p;
  332.     char i_state;
  333.  
  334.     if(q == NULLBUFP || bp == NULLBUF)
  335.         return;
  336.     i_state = dirps();
  337.     if(*q == NULLBUF){
  338.         /* List is empty, stick at front */
  339.         *q = bp;
  340.     } else {
  341.         for(p = *q ; p->anext != NULLBUF ; p = p->anext)
  342.             ;
  343.         p->anext = bp;
  344.     }
  345.     restore(i_state);
  346.     psignal(q,1);
  347. }
  348.  
  349. /* Unlink a packet from the head of the queue */
  350. struct mbuf *dequeue(q)
  351. register struct mbuf **q;
  352. {
  353.     register struct mbuf *bp;
  354.     char i_state;
  355.  
  356.     if(q == NULLBUFP)
  357.         return NULLBUF;
  358.     i_state = dirps();
  359.     if((bp = *q) != NULLBUF){
  360.         *q = bp->anext;
  361.         bp->anext = NULLBUF;
  362.     }
  363.     restore(i_state);
  364.     return bp;
  365. }    
  366.  
  367. /* Copy user data into an mbuf */
  368. struct mbuf *qdata(data,cnt)
  369. char *data;
  370. int16 cnt;
  371. {
  372.     register struct mbuf *bp;
  373.  
  374.     if((bp = alloc_mbuf(cnt)) == NULLBUF)
  375.         return NULLBUF;
  376.     memcpy(bp->data,data,cnt);
  377.     bp->cnt = cnt;
  378.     return bp;
  379. }
  380.  
  381. /* Copy mbuf data into user buffer */
  382. int16 dqdata(bp,buf,cnt)
  383. struct mbuf *bp;
  384. char *buf;
  385. unsigned cnt;
  386. {
  387.     int16 tot;
  388.     unsigned n;
  389.     struct mbuf *bp1;
  390.  
  391.     if(buf == NULLCHAR)
  392.         return 0;
  393.     
  394.     tot = 0;
  395.     for(bp1 = bp;bp1 != NULLBUF; bp1 = bp1->next){
  396.         n = min(bp1->cnt,cnt);
  397.         memcpy(buf,bp1->data,n);
  398.         cnt -= n;
  399.         buf += n;
  400.         tot += n;
  401.     }
  402.     free_p(bp);
  403.     return tot;
  404. }
  405.  
  406. /* Pull a 32-bit integer in host order from buffer in network byte order */
  407. int32 pull32(bpp)
  408. struct mbuf **bpp;
  409. {
  410.     char buf[4];
  411.  
  412.     if(pullup(bpp,buf,4) != 4){
  413.         /* Return zero if insufficient buffer */
  414.         return 0;
  415.     }
  416.     return get32(buf);
  417. }
  418.  
  419. /* Pull a 16-bit integer in host order from buffer in network byte order */
  420. int16 pull16(bpp)
  421. struct mbuf **bpp;
  422. {
  423.     char buf[2];
  424.  
  425.     if(pullup(bpp,buf,2) != 2){
  426.         /* Return zero if insufficient buffer */
  427.         return 0;
  428.     }
  429.     return get16(buf);
  430. }
  431.  
  432. /* Pull single character from mbuf */
  433. char pullchar(bpp)
  434. struct mbuf **bpp;
  435. {
  436.     char c;
  437.  
  438.     if(pullup(bpp,&c,1) != 1)
  439.         /* Return zero if nothing left */
  440.         c = 0;
  441.     return c;
  442. }
  443.  
  444. int write_p(fp,bp)
  445. FILE *fp;
  446. struct mbuf *bp;
  447. {
  448.     while(bp != NULLBUF){
  449.         if(fwrite(bp->data,1,bp->cnt,fp) != bp->cnt)
  450.             return -1;
  451.         bp = bp->next;
  452.     }
  453.     return 0;
  454. }
  455.